﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace DashFire
{
  class ResLevelLoader
  {
    public static ResAsyncInfo LoadLevelAsync(string levelName, LoadSceneMode loadMode = LoadSceneMode.Single)
    {
      ResAsyncInfo info = new ResAsyncInfo();
      info.CurCoroutine = CoroutineProxy.Instance.StartCoroutine(LoadLevelImplAsync(info, levelName, loadMode));
      return info;
    }
    internal static IEnumerator LoadLevelImplAsync(ResAsyncInfo info, string levelName, LoadSceneMode loadMode)
    {
      DFProfiler.Start("LoadLevelImplAsync");
      ResUpdateCallback.OnStartLoad(levelName);

      bool isLoadFromAssetBundle = false;
      AsyncOperation operation = null;

      ClientResVersionData resVersion = ResLoadHelper.GetResVersionDataByAssetName(levelName);
      if (resVersion != null && ResLoadHelper.IsResAssetbundleCached(resVersion.m_AssetBundleName)) {
        isLoadFromAssetBundle = true;
      }
      if (isLoadFromAssetBundle) {
        try {
          string assetBundleUrl = ResLoadHelper.GetFilePath(ResPathType.Cache, resVersion.m_AssetBundleName);
          ResUpdateControler.s_CurSceneAssetbundle = ResUpdateTool.LoadAssetBundle(assetBundleUrl);
          if (ResUpdateControler.s_CurSceneAssetbundle == null) {
            info.IsError = true;
            yield break;
          }
          operation = SceneManager.LoadSceneAsync(resVersion.m_AssetShortName.ToLower(), loadMode);
        } catch (System.Exception ex) {
          ResLoadHelper.Log(string.Format("LoadLevelImplAsync Exception:{0}/{1}", ex.Message, ex.StackTrace));
          info.IsError = true;
          yield break;
        }
      } else {
        operation = SceneManager.LoadSceneAsync(levelName, loadMode);
      }

      while (true)
      {
        if (operation == null || operation.isDone)
        {
          break;
        }
        else
        {
          info.Progress = operation.progress;
          yield return 1;
        }
      }

      DFProfiler.Stop("LoadLevelImplAsync");
      Resources.UnloadUnusedAssets();
      ResUpdateCallback.OnEndLoad(levelName);

      info.IsDone = true;
      info.Progress = 1.0f;
    }
    public static void LoadLevel(string levelName)
    {
      DFProfiler.Start("LoadLevelAsync");
      ResUpdateCallback.OnStartLoad(levelName);

      bool isLoadFromAssetBundle = false;
      ClientResVersionData resVersion = ResLoadHelper.GetResVersionDataByAssetName(levelName);
      if (resVersion != null && ResLoadHelper.IsResAssetbundleCached(resVersion.m_AssetBundleName)) {
        isLoadFromAssetBundle = true;
      }
      if (isLoadFromAssetBundle) {
        AssetBundle assetBundle = null;
        try {
          string assetBundleUrl = ResLoadHelper.GetFilePath(ResPathType.Cache, resVersion.m_AssetBundleName);
          assetBundle = ResUpdateTool.LoadAssetBundle(assetBundleUrl);
          if (assetBundle == null) {
            return;
          }
          SceneManager.LoadScene(resVersion.m_AssetShortName);
        } catch (System.Exception ex) {
          ResLoadHelper.Log(string.Format("LoadLevelImplAsync Exception:{0}/{1}", ex.Message, ex.StackTrace));
          return;
        } finally {
          if (assetBundle != null) {
            assetBundle.Unload(false);
            assetBundle = null;
          }
        }
      } else {
        SceneManager.LoadScene(levelName);
      }

      DFProfiler.Stop("LoadLevelAsync");
      Resources.UnloadUnusedAssets();
      ResUpdateCallback.OnEndLoad(levelName);
    }
    public static ResAsyncInfo PreloadResAssetByLevel(int sceneId)
    {
      ResAsyncInfo info = new ResAsyncInfo();
      info.CurCoroutine = CoroutineProxy.Instance.StartCoroutine(PreloadResAssetByLevelAsync(info, sceneId));
      return info;
    }
    internal static IEnumerator PreloadResAssetByLevelAsync(ResAsyncInfo info, int sceneId)
    {
      Dictionary<int, StaticResCacheData> cacheDataDict = new Dictionary<int, StaticResCacheData>();
      StaticResCacheData levelCacheData = null;
      StaticResCacheDataProvider.Instance.SearchCacheDataByLevelId(sceneId, out levelCacheData, ref cacheDataDict);

      HashSet<string> assetSet = new HashSet<string>();
      if (cacheDataDict != null && cacheDataDict.Count > 0) {
        foreach (StaticResCacheData cacheData in cacheDataDict.Values) {
          assetSet.UnionWith(cacheData.m_AssetNames);
        }
      }

      List<string> assetList = new List<string>(assetSet);
      string assetName = string.Empty;
      if (assetList != null && assetList.Count > 0) {
        for (int idx = 0; idx < assetList.Count; idx++) {
          try {
            assetName = assetList[idx];
            DashFire.ResourceSystem.PreloadSharedResource(assetName);
            info.Progress = 1.0f * idx / assetList.Count;
          } catch (System.Exception ex) {
            ResLoadHelper.ErrLog(string.Format("PreloadResAssetByLevelAsync Exception:{0}/{1}", ex.Message, ex.StackTrace));
          }
          if (idx % ResUpdateConfig.s_PreloadFrameNumMax == 0) {
            yield return 1;
          }
        }
      }
      info.IsDone = true;
      info.Progress = 1.0f;
    }
  }
}
